package hips.gui.parameters;

import hips.Image;
import hips.Partition;
import hips.PixelValue;
import hips.gui.ComponentLocation;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
import javax.swing.JLabel;
import java.awt.Font;
import javax.swing.JButton;
import javax.swing.JRadioButton;
import javax.swing.JTabbedPane;
import java.awt.Component;
import javax.swing.Box;
import java.awt.Dimension;
import javax.swing.JComboBox;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class ParameterFrame extends javax.swing.JFrame {
	private static final long serialVersionUID = 1L;

	Image img;
	Number defaultAlpha;
	Number maxAlpha;
	PixelValue defaultOmega;
	float defaultCindex;
	ParameterPanel[] individualPanel;
	ParameterPanel allPanel;
	int n;
	protected EventListenerList listenerList;

	public ParameterFrame(Image img) {
		initComponents();
		initialize(img);
	}

	private void initialize(Image img) {
		defaultCindex = 0f;
		defaultOmega = Partition.getDefaultOmega(img);
		defaultAlpha = Partition.getDefaultAlpha(img);
		ComponentLocation.setLocationCenter(0.25f, 0.5f, this);
		listenerList = new EventListenerList();

		this.img = img;

		Settings settings = null;
		if (img instanceof hips.images.integer.gray8.ImageGray8)
			settings = new hips.gui.parameters.integer.Settings();
		else
			settings = new hips.gui.parameters.floating.Settings();

		randomPixels.setModel(new SpinnerNumberModel(Partition.RANDOM, 0, img.getSize(), 1));
		iterationsSpinner.setModel(new SpinnerNumberModel(1, 1, 100, 1));

		n = img.getChannels() * img.getSlices();

		cindex.setModel(new SpinnerNumberModel(defaultCindex, 0.0f, 1.0f, settings.STEP_CI));
		individualPanel = new ParameterPanel[n];
		for (int i = 0; i < n; i++) {
			int c = getChannel(i);
			int s = getSlice(i);
			individualPanel[i] = new ParameterPanel(
					(Number) defaultOmega.getValue(s, c),
					img.getMaxValue().range(img.getMinValue()).getValue(s, c),
					defaultAlpha,
					img.getMaxRange().maxValue()
			);
					
		}		
		comboBox.addItem("Original");
		comboBox.addItem("Improved, without connectivity index");
		comboBox.addItem("Improved, with connectivity index");
		comboBox.setSelectedIndex(Partition.IMPROVED_WITH_CINDEX);

		if (n > 1) {
			allPanel = new ParameterPanel(
					defaultOmega.copy().div(n).sum(),
					img.getMaxValue().range(img.getMinValue()).maxValue(),
					defaultAlpha,
					img.getMaxRange().maxValue()
			);
			JSpinner[] omega = new JSpinner[n];
			for (int i = 0; i < n; i++) {
				omega[i] = individualPanel[i].getOmegaSpinner();
			}
			allPanel.getOmegaSpinner().addChangeListener(new ChangeParameterListener(omega));
			JSpinner[] alpha = new JSpinner[n];
			for (int i = 0; i < n; i++) {
				alpha[i] = individualPanel[i].getAlphaSpinner();
			}
			allPanel.getAlphaSpinner().addChangeListener(new ChangeParameterListener(alpha));
		} else {
			jRadioButton1.setEnabled(false);
		}

		jTabbedPane1.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent arg0) {
				if (jTabbedPane1.getTabCount() > 1) {
					int slice = getSlice(jTabbedPane1.getSelectedIndex());
					int channel = getChannel(jTabbedPane1.getSelectedIndex());
					for (int i = 0; i < n; i++) {
						int s = getSlice(i);
						int c = getChannel(i);
						jTabbedPane1.setTitleAt(i, getTitle(s, c, slice, channel));
					}
				}
			};
		});

		setDefaults();
	}

	private int getSlice(int i) {
		return i / img.getChannels();
	}

	private int getChannel(int i) {
		return i % img.getChannels();
	}

	private String getTitle(int slice, int channel, int selectedSlice, int selectedChannel) {
		if (slice == selectedSlice && channel == selectedChannel) {
			if (img.getChannels() == 1) {
				return "  Slice " + slice + "  ";
			}
			if (img.getSlices() == 1) {
				return "  Channel " + channel + "  ";
			}
			return "  (Slice " + slice + ",  Channel " + channel + ")  ";
		}
		if (img.getChannels() == 1) {
			return "  " + slice + "  ";
		}
		if (img.getSlices() == 1) {
			return "  " + channel + "  ";
		}
		return "  (" + slice + ", " + channel + ")  ";
	}

	public void addParameterListener(ParameterListener listener) {
		listenerList.add(ParameterListener.class, listener);
	}

	public void removeParameterListener(ParameterListener listener) {
		listenerList.remove(ParameterListener.class, listener);
	}

	private void setDefaults() {
		cindex.setValue((double) defaultCindex);
		randomPixels.setValue(Partition.RANDOM);
		iterationsSpinner.setValue(1);
		if (img.getSlices() > 1) {
			allPanel.setOmega(defaultOmega.copy().div(n).sum());
		}
		for (int i = 0; i < n; i++) {
			individualPanel[i].setOmega(defaultOmega.getValue(getSlice(i), getChannel(i)));
		}
		jRadioButton1.setSelected(true);
		tabAll();
	}

	private void tabAll() {
		jTabbedPane1.removeAll();
		for (int i = 0; i < n; i++) {
			int c = getChannel(i);
			int s = getSlice(i);
			jTabbedPane1.insertTab(getTitle(s, c, 0, 0), null, individualPanel[i], null, i);
		}
	}

	private void tabOne() {
		jTabbedPane1.removeAll();
		jTabbedPane1.insertTab("All slices and channels", null, allPanel, null, 0);
	}

	public PixelValue getAlpha() {
		PixelValue p = img.newPixelValue();
		for (int i = 0; i < n; i++) {
			int c = getChannel(i);
			int s = getSlice(i);
			p.setValue(individualPanel[i].getAlpha(), s, c);
		}
		return p;
	}

	public int getPartitionMethod() {
		return comboBox.getSelectedIndex();
	}

	public PixelValue getOmega() {
		PixelValue p = img.newPixelValue();
		for (int i = 0; i < n; i++) {
			int c = getChannel(i);
			int s = getSlice(i);
			p.setValue(individualPanel[i].getOmega(), s, c);
		}
		return p;
	}

	public float getCindex() {
		return ((Double) cindex.getValue()).floatValue();
	}

	private void initComponents() {
		setResizable(false);
		setBounds(100, 100, 760, 534);
		jRadioButton1 = new javax.swing.JRadioButton();
		jRadioButton1.setBounds(575, 226, 159, 20);
		jButton1 = new javax.swing.JButton();
		jButton1.setBounds(20, 455, 74, 32);
		jButton2 = new javax.swing.JButton();
		jButton2.setBounds(288, 455, 180, 32);
		jTabbedPane1 = new javax.swing.JTabbedPane();
		jTabbedPane1.setBounds(20, 21, 714, 166);
		jLabel3 = new javax.swing.JLabel();
		jLabel3.setBounds(20, 226, 123, 20);
		cindex = new javax.swing.JSpinner();
		cindex.setBounds(254, 220, 115, 32);
		jButton3 = new javax.swing.JButton();
		jButton3.setBounds(620, 455, 114, 32);

		setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);

		jRadioButton1.setText("Edit individual slices");
		jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				jRadioButton1ActionPerformed(evt);
			}
		});

		jButton1.setText("OK");
		jButton1.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				jButton1ActionPerformed(evt);
			}
		});

		jButton2.setText("Set default values");
		jButton2.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				jButton2ActionPerformed(evt);
			}
		});

		jTabbedPane1.setBackground(new java.awt.Color(246, 246, 246));

		jLabel3.setText("Connectivity index:");

		jButton3.setText("Cancel");
		jButton3.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				jButton3ActionPerformed(evt);
			}
		});

		cindex.setFont(new java.awt.Font("Calibri", 0, 16));
		jButton1.setFont(new java.awt.Font("Calibri", 0, 16));
		jButton2.setFont(new java.awt.Font("Calibri", 0, 16));
		jButton3.setFont(new java.awt.Font("Calibri", 0, 16));
		jLabel3.setFont(new java.awt.Font("Calibri", 0, 16));
		jRadioButton1.setFont(new java.awt.Font("Calibri", 0, 16));
		jTabbedPane1.setFont(new java.awt.Font("Calibri", 0, 16));

		getContentPane().setLayout(null);
		getContentPane().add(jRadioButton1);
		getContentPane().add(jLabel3);
		getContentPane().add(cindex);
		getContentPane().add(jTabbedPane1);
		getContentPane().add(jButton1);
		getContentPane().add(jButton3);
		getContentPane().add(jButton2);

		Component horizontalStrut = Box.createHorizontalStrut(20);
		horizontalStrut.setBounds(0, 0, 10, 405);
		getContentPane().add(horizontalStrut);

		Component verticalStrut = Box.createVerticalStrut(20);
		verticalStrut.setBounds(0, 0, 754, 10);
		getContentPane().add(verticalStrut);

		Component horizontalStrut_1 = Box.createHorizontalStrut(20);
		horizontalStrut_1.setBounds(742, 0, 12, 487);
		getContentPane().add(horizontalStrut_1);

		Component verticalStrut_1 = Box.createVerticalStrut(20);
		verticalStrut_1.setBounds(0, 496, 754, 10);
		getContentPane().add(verticalStrut_1);

		comboBox = new JComboBox();
		comboBox.setFont(new Font("Calibri", Font.PLAIN, 16));
		comboBox.setBounds(180, 397, 275, 20);
		getContentPane().add(comboBox);

		lblPartitioningAlgorithm = new JLabel("Partitioning method:");
		lblPartitioningAlgorithm.setFont(new Font("Calibri", Font.PLAIN, 16));
		lblPartitioningAlgorithm.setBounds(20, 400, 150, 14);
		getContentPane().add(lblPartitioningAlgorithm);

		Component rigidArea_3 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_3.setBounds(20, 198, 20, 20);
		getContentPane().add(rigidArea_3);

		JLabel lblRandomPixelsAl = new JLabel("Random pixels at the beginning:");
		lblRandomPixelsAl.setFont(new Font("Calibri", Font.PLAIN, 16));
		lblRandomPixelsAl.setBounds(20, 334, 224, 14);
		getContentPane().add(lblRandomPixelsAl);

		randomPixels = new JSpinner();
		randomPixels.setFont(new Font("Calibri", Font.PLAIN, 16));
		randomPixels.setBounds(254, 325, 115, 32);
		getContentPane().add(randomPixels);

		iterationsLabel = new JLabel("Iterations of the method:");
		iterationsLabel.setFont(new Font("Calibri", Font.PLAIN, 16));
		iterationsLabel.setBounds(20, 280, 224, 14);
		getContentPane().add(iterationsLabel);

		iterationsSpinner = new JSpinner();
		iterationsSpinner.setFont(new Font("Calibri", Font.PLAIN, 16));
		iterationsSpinner.setBounds(254, 271, 115, 32);
		getContentPane().add(iterationsSpinner);
		
		Component rigidArea = Box.createRigidArea(new Dimension(20, 20));
		rigidArea.setBounds(714, 198, 20, 20);
		getContentPane().add(rigidArea);
		
		Component rigidArea_4 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_4.setBounds(20, 305, 20, 15);
		getContentPane().add(rigidArea_4);
		
		Component rigidArea_2 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_2.setBounds(20, 254, 20, 15);
		getContentPane().add(rigidArea_2);
		
		Component rigidArea_1 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_1.setBounds(20, 359, 20, 30);
		getContentPane().add(rigidArea_1);
	}

	private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
		setDefaults();
	}

	private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
		Object[] listeners = listenerList.getListenerList();
		for (int i = 0; i < listeners.length; i += 2) {
			if (listeners[i] == ParameterListener.class) {
				((ParameterListener) listeners[i + 1]).ParametersOk(getPartitionMethod(), getAlpha(), getOmega(), getCindex(), (Integer) randomPixels.getValue(), (Integer) iterationsSpinner.getValue());
			}
		}
		setVisible(false);
	}

	private void jRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {
		if (jRadioButton1.isSelected()) {
			tabAll();
		} else {
			tabOne();
		}
	}

	private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {
		Object[] listeners = listenerList.getListenerList();
		for (int i = 0; i < listeners.length; i += 2) {
			if (listeners[i] == ParameterListener.class) {
				((ParameterListener) listeners[i + 1]).ParametersCancelled();
			}
		}
		setVisible(false);
	}
	private JSpinner cindex;
	private JButton jButton1;
	private JButton jButton2;
	private JButton jButton3;
	private JLabel jLabel3;
	private JRadioButton jRadioButton1;
	private JTabbedPane jTabbedPane1;
	private JComboBox comboBox;
	private JLabel lblPartitioningAlgorithm;

	public JSpinner randomPixels;
	public JSpinner iterationsSpinner;
	public JLabel iterationsLabel;
}
